﻿using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using LINQToolKit.Web;
using LINQToolKit.Mapping;
using LINQToolKit.Configuration;

namespace LINQToolKit
{
    /// <summary>
    /// Represents the base implements <see cref="IContext"/>
    /// </summary>
    /// <remarks>
    /// This framework is under the GNU licence and Creative Commons 3.0.
    /// You can also get a copy of the source code from google code
    /// <see cref="http://linqtodouban.googlecode.com/svn/trunk/"/>.
    /// For more information and further support, please contact with kevin (chwkai@gmail.com)
    /// </remarks>
    public class DataContext : IContext
    {
        private ContextConfiguration _configuration;
        private IMappingSource _mappingSource;
        public TextWriter Log { get; set; }

        public IMappingSource MappingSource
        {
            get { return this._mappingSource; }
        }

        protected ContextConfiguration Configuration
        {
            get { return this._configuration; }
        }

        public DataContext()
            : this(null, XmlMappingSource.Default)
        {
        }

        public DataContext(IMappingSource mappingSource)
            : this(null, mappingSource)
        {
        }

        public DataContext(ContextConfiguration config, IMappingSource mappingSource)
        {
            mappingSource.AssertNull("mappingSource");

            this._mappingSource = mappingSource;
            this._configuration = config;
        }

        public IEntityProvider CreateProvider()
        {
            IEntityProvider provider = null;

            if (this.Configuration == null || 
                this.Configuration.Provider == null)
            {
                provider = this.CreateDefaultProvider();
            }
            else
            {
                var providerType = this.Configuration.Provider.Type;
                provider = (IEntityProvider)Activator.CreateInstance(
                    providerType, this.MappingSource, this.Configuration.Provider, this.CreateRequest());
                provider.InjectProperties(this.Configuration.Provider.Parameters);
            }

            // set the logger
            provider.Log = this.Log;
            return provider;
        }

        /// <summary>
        /// Returns an instance of request for crud operation
        /// </summary>
        /// <returns></returns>
        public IRequest CreateRequest()
        {
            IRequest request = null;

            if (this.Configuration == null || this.Configuration.Request == null)
            {
                request = new HttpRequestBase();
            }
            else
            {
                request = (IRequest)
                    Activator.CreateInstance(this.Configuration.Request.Type);
                request.InjectProperties(this.Configuration.Request.Parameters);
            }

            return request;
        }

        protected virtual IEntityProvider CreateDefaultProvider()
        {
            return new QueryProvider(this.MappingSource, this.CreateRequest());
        }

        public IEntityTable<T> GetTable<T>()
        {
            var model = this.MappingSource.Entities[typeof(T)];

            return new EntityTable<T>(model, this.CreateProvider());
        }

        public void Dispose()
        {
            // do nothing
        }
    }
}